We will use the Markowitz Portfolio Optimization theory to select an optimal portfolio for us to invest in the tickers listed for Reto Actinver in order to asses the best strategy for winning the trading challenge.
The methodology was:
It is known that the efficient frontier can have multiple portfolios that could be called optimal given the risk-return tradeoff.
[*********************100%***********************] 205 of 205 completed 53 Failed downloads: - GICSA: No data found, symbol may be delisted - VESTA: No data found, symbol may be delisted - QVGMEX: No data found, symbol may be delisted - HCITY: No data found, symbol may be delisted - DLRTRAC: No data found, symbol may be delisted - GMXT: No data found, symbol may be delisted - ARA: No data found, symbol may be delisted - FNOVA: No data found, symbol may be delisted - VMEX: No data found, symbol may be delisted - FUNO: No data found, symbol may be delisted - EDUCA: No data found, symbol may be delisted - CSPX: No data found, symbol may be delisted - GPROFUT: No data found, symbol may be delisted - SIMEC: No data found, symbol may be delisted - GISSA: No data found, symbol may be delisted - OXY1: No data found, symbol may be delisted - VISTA: No data found, symbol may be delisted - FMTY: No data found, symbol may be delisted - NEMAK: No data found, symbol may be delisted - BRKB: No data found, symbol may be delisted - AUTLAN: No data found, symbol may be delisted - MEDICA: No data found, symbol may be delisted - AXTEL: No data found, symbol may be delisted - FIHO: No data found, symbol may be delisted - CETETRC: No data found, symbol may be delisted - DANHOS: No data found, symbol may be delisted - Q: No data found for this date range, symbol may be delisted - KIMBER: No data found, symbol may be delisted - ANGELD: No data found, symbol may be delisted - SRET1: No data found, symbol may be delisted - MFRISCO: No data found, symbol may be delisted - TMM: No data found for this date range, symbol may be delisted - FSHOP: No data found, symbol may be delisted - PINFRA: No data found, symbol may be delisted - TERRA: No data found, symbol may be delisted - FPLUS: No data found, symbol may be delisted - ICH: No data found for this date range, symbol may be delisted - FIBRATC: No data found, symbol may be delisted - DKNG1: No data found, symbol may be delisted - VUAA: No data found, symbol may be delisted - CULTIBA: No data found, symbol may be delisted - IB1MXX: No data found, symbol may be delisted - VINTE: No data found, symbol may be delisted - GBM: No data found for this date range, symbol may be delisted - HOTEL: No data found, symbol may be delisted - SPORT: No data found, symbol may be delisted - ALPEK: No data found, symbol may be delisted - ORBIA: No data found, symbol may be delisted - CORPTRC: No data found, symbol may be delisted - ECAR: No data found, symbol may be delisted - IB01: No data found, symbol may be delisted - VALUEGF: No data found, symbol may be delisted - DIABLOI: No data found, symbol may be delisted
We will unstack the data two times in order to have a stock-date level table in order to have a cleaner data and calculate the returns
df=data.unstack()
df=df.unstack(level=1)
df=df.reset_index()
df=df.rename(columns={'level_0':'stock','level_1':'Date'})
df1=df[['stock','Date','Close']].fillna(0)
df1=df[['stock','Date','Close']].replace(np.nan,0)
df1=df1.loc[df1.Close!=0]
df1['pct_chg']=(df1.groupby("stock")['Close'].apply(pd.Series.pct_change))
df1["log_ret"]=(df1.groupby("stock")['Close'].apply(lambda x:np.log(1+x)))
df1=df1.replace(np.nan,0)
df1.head()
| stock | Date | Close | pct_chg | log_ret | |
|---|---|---|---|---|---|
| 0 | AAL | 2018-04-06 | 49.110222 | 0.000000 | 3.914225 |
| 1 | AAL | 2018-04-09 | 48.651245 | -0.009346 | 3.905023 |
| 2 | AAL | 2018-04-10 | 46.346615 | -0.047370 | 3.857495 |
| 3 | AAL | 2018-04-11 | 44.334938 | -0.043405 | 3.814078 |
| 4 | AAL | 2018-04-12 | 45.477489 | 0.025771 | 3.838968 |
| stock | Date | Close | pct_chg | returns | |
|---|---|---|---|---|---|
| 0 | AAL | 2018-04-06 | 49.110222 | 0.000000 | 3.914225 |
| 1 | AAL | 2018-04-09 | 48.651245 | -0.009346 | 3.905023 |
| 2 | AAL | 2018-04-10 | 46.346615 | -0.047370 | 3.857495 |
| 3 | AAL | 2018-04-11 | 44.334938 | -0.043405 | 3.814078 |
| 4 | AAL | 2018-04-12 | 45.477489 | 0.025771 | 3.838968 |
This will help for getting the Covariance Matrix
| stock | AAL | AAPL | AAXJ | ABNB | ACWI | AFRM | ALFA | AMC | AMD | AMZN | ... | X | XLE | XLF | XLK | XLV | XOM | XPEV | YANG | YINN | ZM |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Date | |||||||||||||||||||||
| 2018-04-09 | -0.009346 | 0.009918 | 0.011941 | NaN | 0.005225 | NaN | 0.044879 | 0.000000 | -0.008325 | 0.000605 | ... | 0.008698 | 0.004751 | 0.005521 | 0.007806 | 0.009890 | 0.000000 | NaN | -0.037163 | 0.034394 | NaN |
| 2018-04-10 | -0.047370 | 0.018818 | 0.020191 | NaN | 0.015592 | NaN | 0.012314 | 0.021276 | 0.047219 | 0.021435 | ... | 0.031331 | 0.033102 | 0.015007 | 0.024632 | 0.016859 | 0.029384 | NaN | -0.093456 | 0.094158 | NaN |
| 2018-04-11 | -0.043405 | -0.004676 | 0.000129 | NaN | -0.004426 | NaN | -0.004943 | -0.005952 | -0.016032 | -0.006385 | ... | -0.031772 | 0.010442 | -0.011900 | -0.005896 | -0.008168 | 0.004671 | NaN | -0.003674 | 0.007384 | NaN |
| 2018-04-12 | 0.025771 | 0.009859 | 0.000257 | NaN | 0.005557 | NaN | 0.013155 | -0.011976 | 0.026477 | 0.015031 | ... | 0.032815 | -0.000142 | 0.017518 | 0.012015 | 0.006760 | -0.002712 | NaN | -0.013232 | 0.008740 | NaN |
| 2018-04-13 | -0.015031 | 0.003388 | -0.009635 | NaN | -0.002211 | NaN | 0.000000 | 0.027273 | -0.014881 | -0.012227 | ... | -0.010312 | 0.011044 | -0.015064 | -0.003306 | -0.000488 | 0.008029 | NaN | 0.036711 | -0.038569 | NaN |
5 rows × 152 columns
df2=df2.fillna(0)
df2=df2.replace(np.nan,0)
data=df2.to_numpy()
cov_mat=df2.cov()*255
weights=np.random.rand(len(df1.stock.unique()),1)
weights=weights/np.sum(weights)
weights=np.array(weights).flatten()
weighRet=np.dot(weights,mean_returns)
What would our return be if we bought one stock off all the ones we queried?
1.0300816026810875
And what about the risk?
0.9868668895858776
Now let's look at a Sharpe Ratio
shp_rt=port_ret/port_risk
print(shp_rt)
1.0437898094983653
This looks like a nice portfolio. However it is rather unreal to have 150 stocks in a portfolio for a trading challenge. We used 10 stock porfolio because one of the rules is to have traded at least in 5 symbols weekly in order to apply for winning the challenge.
stock TQQQ 1.001910 LQDA 1.001444 LABU 1.000206 TZA 0.999146 UNG 0.999715 ACWI 1.000356 FINN 1.000573 XLF 1.000353 TGT 1.000988 JNJ 1.000393 dtype: float64 stock TQQQ LQDA LABU TZA UNG ACWI FINN \ stock TQQQ 0.600041 0.174267 0.587345 -0.489137 0.048426 0.143184 0.025644 LQDA 0.174267 0.907587 0.289693 -0.199281 0.013764 0.045794 0.001139 LABU 0.587345 0.289693 1.155326 -0.643373 0.025481 0.147156 0.024855 TZA -0.489137 -0.199281 -0.643373 0.637168 -0.049682 -0.145619 -0.030945 UNG 0.048426 0.013764 0.025481 -0.049682 0.334412 0.014241 0.002079 ACWI 0.143184 0.045794 0.147156 -0.145619 0.014241 0.041479 0.008057 FINN 0.025644 0.001139 0.024855 -0.030945 0.002079 0.008057 0.045065 XLF 0.140188 0.047766 0.144982 -0.182327 0.018367 0.047240 0.010534 TGT 0.132335 0.043615 0.129791 -0.131337 0.009403 0.035440 0.004753 JNJ 0.071629 0.013850 0.068219 -0.067494 0.008196 0.022469 0.004806 stock XLF TGT JNJ stock TQQQ 0.140188 0.132335 0.071629 LQDA 0.047766 0.043615 0.013850 LABU 0.144982 0.129791 0.068219 TZA -0.182327 -0.131337 -0.067494 UNG 0.018367 0.009403 0.008196 ACWI 0.047240 0.035440 0.022469 FINN 0.010534 0.004753 0.004806 XLF 0.072986 0.039623 0.027305 TGT 0.039623 0.120405 0.021609 JNJ 0.027305 0.021609 0.042295
All portflios look like this. A vector with mean returns and covariance Matrix
/var/folders/z0/5bwd40ds4xq0gh_lytnx56l80000gn/T/ipykernel_20789/2252656341.py:22: RuntimeWarning: invalid value encountered in double_scalars
Iteration: 2 Iteration: 7 Iteration: 119 Iteration: 941 Iteration: 2497 Iteration: 2746 Iteration: 10298 Iteration: 28078
Return: 1274.0534644337909 ***** Max Return Portfolio************* Assets: ['MEGA', 'BND', 'AMC', 'NVDA', 'MEGA', 'CIBR', 'T', 'SHV', 'NKLA'] Weights: [0.20756599 0.00480686 0.13878128 0.02600988 0.30988935 0.0484763 0.00499959 0.09458631 0.16488443] Risk: 37822.1884441336 Return: 1274.0534644337909
Risk: 13997.072406278232 ***** Min Variance Portfolio************* Assets: ['BKCH', 'MEGA', 'DRIP', 'IVV', 'EWZ', 'C', 'CIBR', 'WMT', 'SQ'] Weights: [0.12347134 0.19151248 0.0820306 0.08815962 0.1333816 0.03620419 0.07859314 0.06344978 0.20319725] Risk: 13997.072406278232 Return: 534.5146058524512
***** Max Return Portfolio************* 0 Assets: ['BABA', 'MEGA', 'BOTZ', 'GAP', 'MRO', 'SOFI', 'AMC', 'R', 'MRO'] Weights: [0.0691337 0.17969215 0.15005989 0.1242482 0.173317 0.10182989 0.07943755 0.0462223 0.07605933] Risk: 131.342113159536 Return: 5.0773312631363074
***** Max Return Portfolio************* 1 Assets: ['CIBR', 'LIT', 'ZM', 'SNAP', 'QLD', 'X', 'BYND', 'MEGA', 'PSQ'] Weights: [0.16732598 0.05537036 0.03686758 0.06395675 0.10812245 0.06332081 0.13644738 0.18243715 0.18615154] Risk: 133.34704715025484 Return: 5.139409935116776
***** Max Return Portfolio************* 2 Assets: ['COIN', 'PSQ', 'FAS', 'EWG', 'GCC', 'VRM', 'MEGA', 'C', 'AXP'] Weights: [0.19560471 0.01940906 0.09416493 0.0790135 0.13549929 0.17976723 0.20664032 0.02108621 0.06881476] Risk: 151.03540381645817 Return: 5.687468463201288
***** Max Return Portfolio************* 3 Assets: ['MEGA', 'SOXS', 'VEA', 'COIN', 'SPCE', 'INDA', 'WISH', 'AAL', 'AFRM'] Weights: [0.27500109 0.01331601 0.16474675 0.12841989 0.02906515 0.13509613 0.13369164 0.112317 0.00834634] Risk: 200.99663285399717 Return: 7.238394606937323
***** Max Return Portfolio************* 4 Assets: ['NKLA', 'INTC', 'ATER', 'GLD', 'TSLA', 'IVV', 'MEGA', 'AMC', 'INTC'] Weights: [0.20588079 0.07508909 0.04579737 0.13574733 0.05838878 0.15767583 0.28765449 0.01159391 0.0221724 ] Risk: 210.25511249971532 Return: 7.526631815926474
***** Max Return Portfolio************* 5 Assets: ['MEGA', 'LQDA', 'KOF', 'FAZ', 'MEGA', 'KOF', 'GLD', 'CSCO', 'MEGA'] Weights: [0.12189519 0.05609805 0.09133075 0.11124932 0.15482056 0.13217375 0.0959051 0.15459811 0.08192917] Risk: 262.1205293645444 Return: 9.13707887412889
***** Max Return Portfolio************* 6 Assets: ['SQQQ', 'YANG', 'VNQ', 'UPST', 'TAL', 'SQ', 'SOXL', 'MEGA', 'EWZ'] Weights: [0.05804447 0.16363185 0.09813871 0.04018789 0.02687312 0.15004718 0.02311439 0.39413944 0.04582295] Risk: 288.06991324117706 Return: 9.942551162396056
***** Max Return Portfolio************* 7 Assets: ['BBBY', 'SLV', 'WISH', 'WBD', 'MEGA', 'MEGA', 'AAXJ', 'IVV', 'JNUG'] Weights: [0.11021666 0.02351872 0.06419566 0.12578174 0.22644056 0.21273307 0.07775584 0.03249036 0.12686739] Risk: 320.9902852874021 Return: 10.963765673278404